#pragma once
#include "Socket.hpp"
#include "Log.hpp"
#include <sys/poll.h>
using namespace LogModule;
using namespace SocketModule;

class PollServer
{
    const static int size = 4096;
    const static int defaultfd = -1;

public:
    PollServer(int port) : _listensock(std::make_unique<TcpSocket>()), _isrunning(false)
    {
        _listensock->BuildTcpSocketMethod(port);
        for (int i = 0; i < size; i++)
        {
            _fds[i].fd = defaultfd;
            _fds[i].events = 0;
            _fds[i].revents = 0;
        }
        _fds[0].fd = _listensock->Fd();
        _fds[0].events = POLLIN;
    }
    void Start()
    {
        int timeout = -1;
        _isrunning = true;
        while (_isrunning)
        {
            PrintFd();
            int n = poll(_fds, size, timeout);
            switch (n)
            {
            case -1:
                LOG(LogLevel::ERROR) << "POLL ERROR";
                break;
            case 0:
                LOG(LogLevel::INFO) << "POLL TIME OUT....";
                break;
            default:
                LOG(LogLevel::INFO) << "THERE HAS A FACTOR ALREADY";
                Dispatcher();
                break;
            }
        }
        _isrunning = false;
    }
    void Dispatcher()
    {
        for (int i = 0; i < size; i++)
        {
            if (_fds[i].fd == -1)
            {
                continue;
            }
            if (_fds[i].revents & POLLIN)
            {
                if (_fds[i].fd = _listensock->Fd())
                {
                    Accepter();
                }
                else
                {
                    Recver(i);
                }
            }
        }
    }
    void Accepter()
    {
        InetAddr client;
        int sockfd=_listensock->Accept(&client);
        if(sockfd>0)
        {
            LOG(LogLevel::INFO)<<"GET A NEW LINK,SOCKFD:"
            <<sockfd<<",CLIENT IS: "<<client.StringAddr();
            int pos=0;
            for(;pos<size;pos++)
            {
                if(_fds[pos].fd==defaultfd)
                {
                    break;
                }
            }
            if(pos==size)
            {
                LOG(LogLevel::ERROR)<<"POLL SOCKFD IS FULL";
                close(sockfd);
            }
            else
            {
                _fds[pos].fd=sockfd;
                _fds[pos].events=POLLIN;
                _fds[pos].revents=0;
            }
        }

    }
    void Recver(int pos)
    {
        int sockfd=_fds[pos].fd;
        char buffer[1024];
        int ret=recv(sockfd,buffer,sizeof(buffer),0);
        if(ret>0)
        {
            buffer[ret]=0;
            LOG(LogLevel::INFO)<<"CLIENT SAT#"<<buffer;
        }
        else if(ret==0)
        {
            LOG(LogLevel::WARNING)<<"CLIENT IS CLOSE";
            close(_fds[pos].fd);
            _fds[pos].fd=defaultfd;
            _fds[pos].events=0;
            _fds[pos].revents=0;
        }
        else
        {
            LOG(LogLevel::WARNING)<<"RECVER IS ERROR";
            close(_fds[pos].fd);
            _fds[pos].fd=defaultfd;
            _fds[pos].events=0;
            _fds[pos].revents=0;
        }
    }
    void PrintFd()
    {
        std::cout<<"_FDS[]:"<<std::endl;
        for(int i=0;i<size;i++)
        {
            if(_fds[i].fd==defaultfd)
            {
                continue;
            }
            std::cout<<_fds[i].fd<<" ";
        }
        std::cout<<"\r\n"<<std::endl;

    }
    void Stop()
    {
        _isrunning = false;
    }
    ~PollServer()
    {
    }

private:
    std::unique_ptr<TcpSocket> _listensock;
    bool _isrunning;
    struct pollfd _fds[size];
};